<script lang="tsx">
import {
  PropType,
  defineComponent,
  ref,
  computed,
  unref,
  watch,
  onMounted,
} from "vue";
import {
  ElForm,
  ElFormItem,
  ElRow,
  ElCol,
  FormRules,
  ComponentSize,
  // FormItemProp
} from "element-plus";
import { componentMap } from "./helper/componentMap";
import { propTypes } from "@/utils/propTypes";
import { getSlot } from "@/utils/tsxHelper";
import {
  setTextPlaceholder,
  setGridProp,
  setComponentProps,
  setItemComponentSlots,
  initModel,
} from "./helper";
import { useRenderSelect } from "./components/useRenderSelect";
import { useRenderRadio } from "./components/useRenderRadio";
import { useRenderCheckbox } from "./components/useRenderCheckbox";
import { useDesign } from "@/hooks/web/useDesign";
import { findIndex } from "@/utils";
import { get, set } from "lodash-es";
import { FormProps } from "./types";
import {
  FormSchema,
  FormSetProps,
  ComponentNameEnum,
  SelectComponentProps,
  RadioGroupComponentProps,
  CheckboxGroupComponentProps,
} from "./types";

const { renderSelectOptions } = useRenderSelect();
const { renderRadioOptions } = useRenderRadio();
const { renderCheckboxOptions } = useRenderCheckbox();

const { getPrefixCls } = useDesign();

const prefixCls = getPrefixCls("form");

export default defineComponent({
  name: "Form",
  props: {
    // 生成Form的布局结构数组
    schema: {
      type: Array as PropType<FormSchema[]>,
      default: () => [],
    },
    // 是否需要栅格布局
    isCol: propTypes.bool.def(true),
    // 表单数据对象
    model: {
      type: Object as PropType<any>,
      default: () => ({}),
    },
    // 是否自动设置placeholder
    autoSetPlaceholder: propTypes.bool.def(true),
    // 是否自定义内容
    isCustom: propTypes.bool.def(false),
    // 表单label宽度
    labelWidth: propTypes.oneOfType([String, Number]).def("auto"),
    rules: {
      type: Object as PropType<FormRules>,
      default: () => ({}),
    },
    labelPosition: propTypes.oneOf(["left", "right", "top"]).def("right"),
    labelSuffix: propTypes.string.def(""),
    hideRequiredAsterisk: propTypes.bool.def(false),
    requireAsteriskPosition: propTypes.oneOf(["left", "right"]).def("left"),
    showMessage: propTypes.bool.def(true),
    inlineMessage: propTypes.bool.def(false),
    statusIcon: propTypes.bool.def(false),
    validateOnRuleChange: propTypes.bool.def(true),
    size: {
      type: String as PropType<ComponentSize>,
      default: undefined,
    },
    disabled: propTypes.bool.def(false),
    scrollToError: propTypes.bool.def(false),
    scrollToErrorOffset: propTypes.oneOfType([Boolean, Object]).def(undefined),
    // onValidate: {
    //   type: Function as PropType<(prop: FormItemProp, isValid: boolean, message: string) => void>,
    //   default: () => {}
    // }
  },
  emits: ["register"],
  setup(props, { slots, expose, emit }) {
    // element form 实例
    const elFormRef = ref<ComponentRef<typeof ElForm>>();

    const mergeProps = ref<FormProps>({});

    const getProps = computed(() => {
      const propsObj = { ...props };
      Object.assign(propsObj, unref(mergeProps));
      return propsObj;
    });

    // 存储表单实例
    const formComponents = ref({});

    // 存储form-item实例
    const formItemComponents = ref({});

    // 表单数据
    const formModel = ref<Recordable>(props.model);

    onMounted(() => {
      emit("register", unref(elFormRef)?.$parent, unref(elFormRef));
    });

    // 对表单赋值
    const setValues = (data: Recordable = {}) => {
      formModel.value = Object.assign(unref(formModel), data);
    };

    const setProps = (props: FormProps = {}) => {
      mergeProps.value = Object.assign(unref(mergeProps), props);
    };

    const delSchema = (field: string) => {
      const { schema } = unref(getProps);

      const index = findIndex(schema, (v: FormSchema) => v.field === field);
      if (index > -1) {
        schema.splice(index, 1);
      }
    };

    const addSchema = (formSchema: FormSchema, index?: number) => {
      const { schema } = unref(getProps);
      if (index !== void 0) {
        schema.splice(index, 0, formSchema);
        return;
      }
      schema.push(formSchema);
    };

    const setSchema = (schemaProps: FormSetProps[]) => {
      const { schema } = unref(getProps);
      for (const v of schema) {
        for (const item of schemaProps) {
          if (v.field === item.field) {
            set(v, item.path, item.value);
          }
        }
      }
    };

    const getOptions = async (fn: Function, item: FormSchema) => {
      const options = await fn();
      if (!options || options.length == 0) return;
      setSchema([
        {
          field: item.field,
          path:
            item.component === ComponentNameEnum.TREE_SELECT ||
            item.component === ComponentNameEnum.TRANSFER
              ? "componentProps.data"
              : "componentProps.options",
          value: options,
        },
      ]);
    };

    /**
     * @description: 获取表单组件实例
     * @param filed 表单字段
     */
    const getComponentExpose = (filed: string) => {
      return unref(formComponents)[filed];
    };

    /**
     * @description: 获取formItem实例
     * @param filed 表单字段
     */
    const getFormItemExpose = (filed: string) => {
      return unref(formItemComponents)[filed];
    };

    const setComponentRefMap = (ref: any, filed: string) => {
      formComponents.value[filed] = ref;
    };

    const setFormItemRefMap = (ref: any, filed: string) => {
      formItemComponents.value[filed] = ref;
    };

    expose({
      setValues,
      formModel,
      setProps,
      delSchema,
      addSchema,
      setSchema,
      getComponentExpose,
      getFormItemExpose,
    });

    // 监听表单结构化数组，重新生成formModel
    watch(
      () => unref(getProps).schema,
      (schema = []) => {
        formModel.value = initModel(schema, unref(formModel));
      },
      {
        immediate: true,
        deep: true,
      }
    );

    // 渲染包裹标签，是否使用栅格布局
    const renderWrap = () => {
      const { isCol } = unref(getProps);
      const content = isCol ? (
        <ElRow gutter={20}>{renderFormItemWrap()}</ElRow>
      ) : (
        renderFormItemWrap()
      );
      return content;
    };

    // 是否要渲染el-col
    const renderFormItemWrap = () => {
      // hidden属性表示隐藏，不做渲染
      const { schema = [], isCol } = unref(getProps);

      return schema
        .filter((v) => !v.remove)
        .map((item) => {
          // 如果是 Divider 组件，需要自己占用一行
          const isDivider = item.component === "Divider";
          const Com = componentMap["Divider"] as ReturnType<
            typeof defineComponent
          >;
          return isDivider ? (
            <Com {...{ contentPosition: "left", ...item.componentProps }}>
              {item?.label}
            </Com>
          ) : isCol ? (
            // 如果需要栅格，需要包裹 ElCol
            <ElCol {...setGridProp(item.colProps)}>
              {renderFormItem(item)}
            </ElCol>
          ) : (
            renderFormItem(item)
          );
        });
    };

    // 渲染formItem
    const renderFormItem = (item: FormSchema) => {
      // 如果有optionApi，优先使用optionApi, 并且options不存在或者为空数组
      if (
        item.optionApi &&
        (!item.componentProps?.options || !item.componentProps?.options.length)
      ) {
        // 内部自动调用接口，不影响其它渲染
        getOptions(item.optionApi, item);
      }
      const formItemSlots: Recordable = {
        default: () => {
          if (item?.formItemProps?.slots?.default) {
            return item?.formItemProps?.slots?.default(formModel.value);
          } else {
            const Com = componentMap[item.component as string] as ReturnType<
              typeof defineComponent
            >;

            const { autoSetPlaceholder } = unref(getProps);

            const componentSlots = (item?.componentProps as any)?.slots || {};
            const slotsMap: Recordable = {
              ...setItemComponentSlots(componentSlots),
            };
            // // 如果是select组件，并且没有自定义模板，自动渲染options
            if (item.component === ComponentNameEnum.SELECT) {
              slotsMap.default = !componentSlots.default
                ? () => renderSelectOptions(item)
                : () => {
                    return componentSlots.default(
                      unref(
                        (item?.componentProps as SelectComponentProps)?.options
                      )
                    );
                  };
            }

            // 虚拟列表
            if (
              item.component === ComponentNameEnum.SELECT_V2 &&
              componentSlots.default
            ) {
              slotsMap.default = ({ item }) => {
                return componentSlots.default(item);
              };
            }

            // 单选框组和按钮样式
            if (
              item.component === ComponentNameEnum.RADIO_GROUP ||
              item.component === ComponentNameEnum.RADIO_BUTTON
            ) {
              slotsMap.default = !componentSlots.default
                ? () => renderRadioOptions(item)
                : () => {
                    return componentSlots.default(
                      unref(
                        (item?.componentProps as CheckboxGroupComponentProps)
                          ?.options
                      )
                    );
                  };
            }

            // 多选框组和按钮样式
            if (
              item.component === ComponentNameEnum.CHECKBOX_GROUP ||
              item.component === ComponentNameEnum.CHECKBOX_BUTTON
            ) {
              slotsMap.default = !componentSlots.default
                ? () => renderCheckboxOptions(item)
                : () => {
                    return componentSlots.default(
                      unref(
                        (item?.componentProps as RadioGroupComponentProps)
                          ?.options
                      )
                    );
                  };
            }
            // 特殊处理 Cascader 组件，确保 props 配置正确传递

            const Comp = () => {
              // 如果field是多层路径，需要转换成对象
              const itemVal = computed({
                get: () => {
                  return get(formModel.value, item.field);
                },
                set: (val) => {
                  set(formModel.value, item.field, val);
                },
              });
              // 特殊处理 Cascader 组件，确保正确的属性绑定
              if (item.component === "Cascader") {
                const cascaderProps = {
                  ...(autoSetPlaceholder && setTextPlaceholder(item)),
                  ...setComponentProps(item),
                  modelValue: itemVal.value,
                  "onUpdate:modelValue": (val: any) => {
                    itemVal.value = val;
                  },
                  style: item.componentProps?.style || { width: "100%" },
                };

                return (
                  <Com
                    ref={(el: any) => setComponentRefMap(el, item.field)}
                    {...cascaderProps}
                  >
                    {{ ...slotsMap }}
                  </Com>
                );
              }
              return item.component === ComponentNameEnum.UPLOAD ? (
                <Com
                  vModel:file-list={itemVal.value}
                  ref={(el: any) => setComponentRefMap(el, item.field)}
                  {...(autoSetPlaceholder && setTextPlaceholder(item))}
                  {...setComponentProps(item)}
                  style={
                    item.componentProps?.style || {
                      width: "100%",
                    }
                  }
                >
                  {{ ...slotsMap }}
                </Com>
              ) : (
                <Com
                  vModel={itemVal.value}
                  ref={(el: any) => setComponentRefMap(el, item.field)}
                  {...(autoSetPlaceholder && setTextPlaceholder(item))}
                  {...setComponentProps(item)}
                  style={
                    item.componentProps?.style || {
                      width: "100%",
                    }
                  }
                >
                  {{ ...slotsMap }}
                </Com>
              );
            };

            return <>{Comp()}</>;
          }
        },
      };
      if (item?.formItemProps?.slots?.label) {
        formItemSlots.label = (...args: any[]) => {
          return (item?.formItemProps?.slots as any)?.label(...args);
        };
      }
      if (item?.formItemProps?.slots?.error) {
        formItemSlots.error = (...args: any[]) => {
          return (item?.formItemProps?.slots as any)?.error(...args);
        };
      }
      return (
        <ElFormItem
          v-show={!item.hidden}
          ref={(el: any) => setFormItemRefMap(el, item.field)}
          {...(item.formItemProps || {})}
          prop={item.field}
          label={item.label || ""}
        >
          {formItemSlots}
        </ElFormItem>
      );
    };

    // 过滤传入Form组件的属性
    // 过滤传入Form组件的属性
    // 过滤传入Form组件的属性
    const getFormBindValue = () => {
      const delKeys = [
        "schema",
        "isCol",
        "autoSetPlaceholder",
        "isCustom",
        "model",
      ];
      const props = { ...unref(getProps) };

      for (const key in props) {
        if (delKeys.indexOf(key) !== -1) {
          delete props[key];
        }
      }

      // 更严格的 labelWidth 处理
      const processLabelWidth = (width: string | number): string => {
        // 处理空值、undefined、null
        if (width === undefined || width === null || width === "") {
          return "auto";
        }

        // 处理 "auto" 字符串
        if (width === "auto") {
          return "auto";
        }

        // 处理数字和数字字符串
        const numWidth = Number(width);

        // 如果是有效的数字且大于等于0
        if (!isNaN(numWidth) && numWidth >= 0) {
          return numWidth + "px";
        }

        // 如果已经是带px的值且格式正确
        if (typeof width === "string" && width.endsWith("px")) {
          const pxValue = Number(width.replace("px", ""));
          if (!isNaN(pxValue) && pxValue >= 0) {
            return width;
          }
        }

        console.warn(`[Form] Invalid labelWidth: ${width}, using 'auto'`);
        return "auto";
      };

      // props.labelWidth = processLabelWidth(props.labelWidth);
      props.labelWidth = "auto";
      return props as FormProps;
    };

    return () => (
      <ElForm
        ref={elFormRef}
        {...getFormBindValue()}
        model={unref(getProps).isCustom ? unref(getProps).model : formModel}
        class={prefixCls}
        // @ts-ignore
        onSubmit={(e: Event) => {
          e.preventDefault();
        }}
      >
        {{
          // 如果需要自定义，就什么都不渲染，而是提供默认插槽
          default: () => {
            const { isCustom } = unref(getProps);
            return isCustom ? getSlot(slots, "default") : renderWrap();
          },
        }}
      </ElForm>
    );
  },
});
</script>

<style lang="less" scoped>
.@{elNamespace}-form.@{adminNamespace}-form .@{elNamespace}-row {
  margin-right: 0 !important;
  margin-left: 0 !important;
}

.@{elNamespace}-form--inline {
  :deep(.el-form-item__content) {
    & > :first-child {
      min-width: 229.5px;
    }
  }
  .@{elNamespace}-input-number {
    // 229.5px是兼容el-input-number的最小宽度,
    min-width: 229.5px;
  }
}
</style>
